/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef OHMW_INTERFACE_NAPI_TIME_H
#define OHMW_INTERFACE_NAPI_TIME_H

#include "framework/c++/bincode/Decoder.h"
#include "framework/c++/bincode/Encoder.h"
#include "napi_utils.h"
#include "BaseMessage.h"
#include <cstdint>
#include <vector>

namespace OHOS {
namespace OHMW_NAPI {
class Time : public BaseMessage {
public:
    Time() : BaseMessage(std::string(MESSAGE_TIME)) {}

    static napi_ref constructor_;

    napi_ref secs = nullptr;
    napi_ref nano_secs = nullptr;

    static napi_value Constructor(napi_env env, napi_callback_info info) {
        NAPI_CHECKOUT_ARGS0;
        Time *obj = new Time();
        obj->KeepEnv(env, thisVar);

        napi_wrap(env, thisVar, reinterpret_cast<void *>(obj), Time::Destructor, nullptr, nullptr);

        napi_value __type;
        napi_create_string_utf8(env, MESSAGE_TIME, NAPI_AUTO_LENGTH, &__type);
        napi_set_named_property(env, thisVar, "__type", __type);

        NAPI_PACKAGE_UINT32(napiSecs, 0);
        napi_set_named_property(env, thisVar, "secs", napiSecs);

        NAPI_PACKAGE_UINT32(napiNanoSecs, 0);
        napi_set_named_property(env, thisVar, "nano_secs", napiNanoSecs);

        napi_value napiEncode;
        napi_create_function(env, nullptr, 0, Time::NapiEncode, nullptr, &napiEncode);
        napi_set_named_property(env, thisVar, "Encode", napiEncode);
        
        napi_value napiDecode;
        napi_create_function(env, nullptr, 0, Time::NapiDecode, nullptr, &napiDecode);
        napi_set_named_property(env, thisVar, "Decode", napiDecode);

        return thisVar;
    }

    static void Destructor(napi_env env, void *data, void *hint) {
        Time *obj = static_cast<Time *>(data);
        delete obj;
    }

    static napi_value NapiInstance(napi_env env) {
        napi_value instance;
        napi_value constructor;
        napi_get_reference_value(env, Time::constructor_, &constructor);
        napi_new_instance(env, constructor, 0, nullptr, &instance);
        return instance;
    }

    static napi_value NapiEncode(napi_env env, napi_callback_info info) {
        NAPI_CHECKOUT_ARGS0;
        Time *obj;
        napi_unwrap(env, thisVar, (void **)&obj);

        std::vector<uint8_t> buffer;
        OHMW::DefaultEncoder encoder;
        bool result = obj->Encode(encoder, buffer, env);
        if (!result) {
            return nullptr;
        }

        napi_value napiBuffer;
        void *data;
        napi_create_buffer(env, buffer.size(), &data, &napiBuffer);
        memcpy(data, buffer.data(), buffer.size());

        return napiBuffer;
    }

    static napi_value NapiDecode(napi_env env, napi_callback_info info) {
        NAPI_CHECKOUT_ARGS(1);
        Time *obj;
        napi_unwrap(env, thisVar, (void **)&obj);

        NAPI_CHECKOUT_BUFFER(napiBuffer, napiBufferLength, args[0]);
        
        std::vector<uint8_t> buffer(napiBuffer, napiBuffer + napiBufferLength);
        OHMW::DefaultDecoder decoder;
        bool result = obj->Decode(decoder, buffer);
        
        NAPI_PACKAGE_BOOL(ret, result);
        return ret;
    }

    template<typename E>
    bool Encode(E &encoder, std::vector<uint8_t> &buffer, napi_env env) {
        napi_value thisVar;
        napi_get_reference_value(env, thisVar_, &thisVar);

        napi_value napiSecs;
        napi_get_named_property(env, thisVar, "secs", &napiSecs);
        NAPI_CHECKOUT_UINT32(secs, napiSecs);
        
        if (!encoder.Put(buffer, secs)) {
            return false;
        }
        
        napi_value napiNanoSecs;
        napi_get_named_property(env, thisVar, "nano_secs", &napiNanoSecs);
        NAPI_CHECKOUT_UINT32(nanoSecs, napiNanoSecs);
        if (!encoder.Put(buffer, nanoSecs)) {
            return false;
        }
        
        return true;
    }
    
    template<typename D>
    bool Decode(D &decoder, const std::vector<uint8_t> &buffer) {
        napi_env env = env_;
        napi_value thisVar;
        napi_get_reference_value(env, thisVar_, &thisVar);

        uint32_t secs;
        if (!decoder.Get(buffer, secs)) {
            return false;
        }
        
        uint32_t nanoSecs;
        if (!decoder.Get(buffer, nanoSecs)) {
            return false;    
        }
        
        NAPI_PACKAGE_UINT32(napiSecs, secs);
        napi_set_named_property(env, thisVar, "secs", napiSecs);
        
        NAPI_PACKAGE_UINT32(napiNanoSecs, nanoSecs);
        napi_set_named_property(env, thisVar, "nano_secs", napiNanoSecs);
        
        return true;
    }
};
} // namespace OHMW_NAPI
} // namespace OHOS

#endif
